package com.arpa.ntocc.common.common.exception;

import com.arpa.core.web.RestFulStatus;
import com.arpa.core.web.Result;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

/**
 * 全局异常处理
 * @Author liuyj
 * @Date 2019-11-07 18:50:46
 */
@ControllerAdvice
@Log4j2
public class GlobalExceptionHandler {

	/**
	 * 参数不能为空
	 */
	@ExceptionHandler(MissingServletRequestParameterException.class)
	@ResponseBody
	public Result bindException(MissingServletRequestParameterException exception) {
		log.error("MissingServletRequestParameterException:",exception);
		return Result.error(400, String.format("参数%s不能为空！", exception.getParameterName()));
	}

	/**
	 * 参数校验错误
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseBody
	public Result bindException(MethodArgumentNotValidException exception) {
		BindingResult bindingResult = exception.getBindingResult();
		FieldError fieldError = bindingResult.getFieldError();
		String msg = "处理参数时异常";
		if (fieldError != null) {
			msg = fieldError.getDefaultMessage();
		}

		log.error("MethodArgumentNotValidException:",exception);
		return Result.error(400, String.format("参数校验错误:%s", msg));
	}

	//注释掉具体错误异常，解决等保测试出的2个高危漏洞：
	// 目标URL存在框架注入漏洞 http://localhost/ntocc-site-api/home/orderList?pageNum=50%23%2A%2F--%3E%27%22%29%3B%3E%3CIFRAME%2FSRC%3Dhttp%3A%2F%2Fwww.baidu.com%2Fzqpuf.html%3E
	// 目标URL存在链接注入漏洞 http://localhost/ntocc-site-api/home/orderList?pageSize=50%23%2A%2F--%3E%27%22%29%3B%3E%3Ca%2Fhref%3D%2Flgtrb.html%3ELinkInjTest%3C%2Fa%3E
	/**
	 * 参数校验错误
	 */
	@ExceptionHandler(BindException.class)
	@ResponseBody
	public Result bindException(BindException exception) {
		FieldError fieldError = exception.getBindingResult().getFieldError();
		exception.printStackTrace();
		fieldError.getRejectedValue();
		log.error("BindException:",exception);
		return Result.error(400, String.format("参数校验错误:%s", fieldError.getDefaultMessage()));
	}

	/**
	 * 登录异常处理
	 */
	@ExceptionHandler(AuthorizeTokenException.class)
	@ResponseBody
	public Result bindException(AuthorizeTokenException authorizeTokenException) {
		log.error("AuthorizeTokenException:",authorizeTokenException);
		return Result.error(RestFulStatus.OAUTH2_ACCESS_TOKEN_CHECK_FAILE);
	}

	/**
	 * 角色不足
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(RoleException.class)
	@ResponseBody
	public Result bindException(RoleException exception) {
		log.error("RoleException:",exception);
		return Result.error(401, exception.getMessage());
	}

	/**
	 * 权限不足
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(PermissionException.class)
	@ResponseBody
	public Result bindException(PermissionException exception) {
		log.error("PermissionException:",exception);
		return Result.error(401, exception.getMessage());
	}

	/**
	 * 账号禁用
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(DisabledAccountException.class)
	@ResponseBody
	public Result bindException(DisabledAccountException exception) {
		log.error("DisabledAccountException:",exception);
		return Result.error(RestFulStatus.OAUTH2_ACCOUNT_DISABLED);
	}

	/**
	 * 账号不存在
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(UnknownAccountException.class)
	@ResponseBody
	public Result bindException(UnknownAccountException exception) {
		log.error("UnknownAccountException:",exception);
		return Result.error(RestFulStatus.OAUTH2_AUTHORIZE_INVALID);
	}

	/**
	 * 缺少参数异常
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(MissingRequestHeaderException.class)
	@ResponseBody
	public Result bindException(MissingRequestHeaderException exception) {
		log.error("MissingRequestHeaderException:",exception);
		return Result.error(400, String.format("参数%s不能为空！",  exception.getHeaderName()));
	}

	/**
	 * 缺少body异常
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(HttpMessageNotReadableException.class)
	@ResponseBody
	public Result bindException(HttpMessageNotReadableException exception) {
		log.error("HttpMessageNotReadableException:",exception);
		return Result.error(400, String.format("缺少request body！",  exception.getMessage()));
	}

	/**
	 * 请求方式异常
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	@ResponseBody
	public Result bindException(HttpRequestMethodNotSupportedException exception) {
		log.error("HttpRequestMethodNotSupportedException:",exception);
		return Result.error(400, String.format("请求方式异常",  exception.getMessage()));
	}

	/**
	 * 校验参数异常
	 * @param exception
	 * @return
	 */
	@ExceptionHandler(ValidationException.class)
	@ResponseBody
	public Result bindException(ValidationException exception) {
		log.error("ValidationException:",exception);
		if(exception instanceof ConstraintViolationException) {
			return Result.error(400, String.format("参数%s不能为空！", ((ConstraintViolationException) exception).getConstraintViolations()));
		}
		return Result.error(400, String.format("参数%s不能为空！", exception.getCause()));
	}

	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseBody
	public Result bindException(ConstraintViolationException exception) {
		exception.printStackTrace();
		StringBuffer message = new StringBuffer();
		for(ConstraintViolation<?> entity : exception.getConstraintViolations()) {
			if(message.length()>0) {
				message.append(";");
			}
			message.append(entity.getMessage());
		}
		return Result.error(400, message.toString());
	}

	/**
	 * 异常处理
	 */
	@ExceptionHandler(ServiceException.class)
	@ResponseBody
	public Result bindException(HttpServletRequest request, ServiceException exception) {
		log.error("ServiceException:",exception);
		return Result.error(400, exception.getMessage());
	}


	/**
	 * 异常处理
	 */
	@ExceptionHandler(Exception.class)
	@ResponseBody
	public Result bindException(HttpServletRequest request, Exception exception) {
		log.error("Exception:",exception);
		return Result.error(RestFulStatus.INTERNAL_SERVER_ERROR);
	}

	/**
	 * 保存时主键已存在异常
	 */
	@ExceptionHandler(DuplicateKeyException.class)
	@ResponseBody
	public Result SqlException(DuplicateKeyException exception) {
		log.error("DuplicateKeyException:",exception);
		return Result.error(400, "保存时主键已存在！");
	}

}
